package jehc.djshi.oauth.client;
import jehc.djshi.common.annotation.Auth;
import jehc.djshi.common.annotation.AuthUneedLogin;
import jehc.djshi.common.annotation.NeedLoginUnAuth;
import jehc.djshi.common.base.BaseResult;
import jehc.djshi.common.base.BaseUtils;
import jehc.djshi.common.base.InitBean;
import jehc.djshi.common.constant.SessionConstant;
import jehc.djshi.common.constant.StatusConstant;
import jehc.djshi.common.entity.InputEntity;
import jehc.djshi.common.util.JsonUtil;
import jehc.djshi.oauth.client.service.AuthService;
import lombok.extern.slf4j.Slf4j;
import net.sf.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import javax.servlet.http.HttpServletRequest;
import org.springframework.core.MethodParameter;
import org.springframework.core.NamedThreadLocal;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
/**
 * @Desc 采用自定义注解做权限
 * 做互联网前端需要该方法（只要在方法名上加@AuthUneedLogin则表示无需登录或不加也表示无需登录，若加@AuthNeedLogin则表示需要登录才可以访问）
 * @Author 邓纯杰
 * @CreateTime 2012-12-12 12:12:12
 */
@Slf4j
public class AuthHandler extends BaseUtils implements HandlerInterceptor {
	private static final ThreadLocal<Long> startTimeThreadLocal = new NamedThreadLocal<Long>("ThreadLocal StartTime");
	@Autowired
	AuthService authService;

	@Autowired
	InitBean initBean;
	/**
	 * 前置通知
	 */
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
		//1.开始时间
		long beginTime = System.currentTimeMillis();
		//线程绑定变量（该数据只有当前请求的线程可见）
		startTimeThreadLocal.set(beginTime);
		String url = null;
		HandlerMethod methodHandler = null;
		try {
			if (HttpMethod.OPTIONS.toString().equals(request.getMethod())) {
				log.info("放行OPTIONS探针请求");
				return true;
			}
			url = request.getRequestURI().replace(request.getContextPath(), "");
			methodHandler=(HandlerMethod) handler;
			/*
			Map<String,?> map = (Map<String,?>)request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
			GetMapping mapping = methodHandler.getMethodAnnotation(GetMapping.class);
			log.info("URL is {}", Arrays.toString(mapping.value()));
			*/
			InputEntity inputEntity = new InputEntity();
			inputEntity.setUrl(url);
			AuthUneedLogin authUneedLogin=methodHandler.getMethodAnnotation(AuthUneedLogin.class);
			NeedLoginUnAuth needLoginUnAuth = methodHandler.getMethodAnnotation(NeedLoginUnAuth.class);
			Auth aunth = methodHandler.getMethodAnnotation(Auth.class);
			if(null != aunth){
				inputEntity.setUrl(aunth.value());
			}
			if(null != authUneedLogin){
				return true;
			}
			if(null != needLoginUnAuth){
				inputEntity.setNeedLoginUnAuth("NeedLoginUnAuth");
			}
			inputEntity.setToken(getClientToken(request));
//			//手动设置秘钥
//			Map<String,String> map = new HashMap<>();
//			map.put(CacheConstant.JEHC_CLOUD_KEY,initBean.getJehcCloudKey());
//			map.put(CacheConstant.JEHC_CLOUD_SECURITY,initBean.getJehcCloudSecurity());
//			BaseResult baseResult = restTemplateUtil.post(restTemplateUtil.restOauthURL()+"/oauth",BaseResult.class,inputEntity, restTemplateUtil.setHeaders(request,map));
			BaseResult baseResult = authService.oauth(request,inputEntity);
			Long endTime = System.currentTimeMillis();
			log.info("授权中心耗时："+(endTime-beginTime)+" ms");
			if(baseResult.getSuccess()){
				return true;
			}else{
				outPrint(response,baseResult);
				return false;
			}
		} catch (Exception e) {
			outPrint(response,new BaseResult(StatusConstant.XT_PT_STATUS_VAL_500,"拦截器出现异常:"+e.getLocalizedMessage(),false));
			log.debug("Request URI: {}, 异常信息: {}", url, e.getMessage());
			return false;
		}
	}
	


	/**
	 * 后置通知
	 */
	public void afterCompletion(HttpServletRequest request,HttpServletResponse response,Object handler,Exception ex) throws Exception {
		//得到线程绑定的局部变量（开始时间）
		long beginTime = startTimeThreadLocal.get();
		startTimeThreadLocal.remove();
		//结束时间  
		long endTime = System.currentTimeMillis(); 	
        //耗时
        long usedTime = (endTime - beginTime);
        //URI
        String uri = request.getRequestURI().replace(request.getContextPath(), "");
        //最大内存(单位m)
        long maxMemory = Runtime.getRuntime().maxMemory()/1024/1024;
        //已分配内存
        long totalMemory = Runtime.getRuntime().totalMemory()/1024/1024;
        //已分配内存中的剩余空间
        long freeMemory = Runtime.getRuntime().freeMemory()/1024/1024;
        //最大可用内存
        long useMemory= (Runtime.getRuntime().maxMemory()-Runtime.getRuntime().totalMemory()+Runtime.getRuntime().freeMemory())/1024/1024;
        StringBuilder sbuilder = new StringBuilder();
        if(handler instanceof HandlerMethod){
            HandlerMethod handlerMethod = (HandlerMethod)handler;
            MethodParameter[] methodParameters = handlerMethod.getMethodParameters();
            for(MethodParameter methodParameter : methodParameters){
            	sbuilder.append(methodParameter.getParameterName());
            }
        }
		log.info("[拦截器日志处理类：{}","{\"开始时间\":\""+beginTime+"\",计时结束\":\""+endTime+"\",\"耗时\":\""+usedTime+"\",\"最大内存(单位m)\":\""+maxMemory+"\",\"已分配内存\":\""+totalMemory+"\",\"已分配内存中的剩余空间\":\""+freeMemory+"\",\"最大可用内存\":\""+useMemory+"\",\"参数\":\""+sbuilder.toString()+"\",\"uri\":\""+uri+"\"}]");
	}
	/**
	 * 环绕通知
	 */
	public void postHandle(HttpServletRequest request,
			HttpServletResponse response,
			Object handler, 
			ModelAndView modelAndView) throws Exception {
		if (null != modelAndView){
			modelAndView.getViewName();
		}
	}

	/**
	 *
	 * @param response
	 * @param baseResult
	 */
	private void outPrint(HttpServletResponse response,BaseResult baseResult){
		try {
			response.setContentType("application/json;charset=utf-8");
			PrintWriter writer = response.getWriter();
			Map<String,Object> map = new HashMap<>();
			map.put("status",baseResult.getStatus());
			map.put("message",baseResult.getMessage());
			JSONObject json = JsonUtil.toJsonObj(map);
			writer.write(json.toString());
			writer.flush();
			writer.close();
		} catch (Exception e) {
			log.error("jehc out print exception",e);
		}
	}

	/**
	 * 获取客户端token
	 * @param request
	 * @return
	 */
	public String getClientToken(HttpServletRequest request) {
		HttpHeaders headers = new HttpHeaders();
		Enumeration<String> headerNames = request.getHeaderNames();
		while (headerNames.hasMoreElements()) {
			String key = (String) headerNames.nextElement();
			String value = request.getHeader(key);
			headers.add(key, value);
		}
		String token = request.getHeader(SessionConstant.TOKEN);
		return token;
	}
}